public class Rally extends Tileable {
	Map m;
	public Unit[] battleUnits;
	public Unit[] supportUnits;
	public Unit[] allUnits;
	public int battleSize;
	public int supportSize;
	public int size;
	public int clockStep;
	public int offensive;
	public int defensive;
	public int armor;
	public int movement;
	int moveDelay;
	public int health;
	public int upkeep;
	public int rawUpkeep;
	public Player player;
	public int dir;
	public String mode;
	public int powerDelay = 0;
	public RTSQueue<Character> movementQueue; // to be changed to Queue
	public RTSQueue<int[]> commandQueue; // to be changed to Queue

	public Rally(int _id, Player player, Map m) {
		this.m=m;
		this.type = 30;
		this.ID = _id;
		this.player = player;
		this.battleUnits = new Unit[25];
		this.supportUnits = new Unit[25];
		this.allUnits = new Unit[25];
		this.battleSize = 0;
		this.supportSize = 0;
		this.offensive = 0;
		this.defensive = 0;
		this.armor = 0;
		this.movement = 0;
		this.health = 0;
		this.rawUpkeep = 0;
		this.mode = "WAIT";
		this.commandQueue = new RTSQueue<int[]>();
	}

	public void disband() {
		for (int i = 0; i < 10; i++) {
			if (this.battleUnits[i] != null) {
				this.battleUnits[i].setRally(null);
				this.battleUnits[i] = null;
			}
			if (this.supportUnits[i] != null) {
				this.supportUnits[i].setRally(null);
				this.supportUnits[i] = null;
			}
			this.battleSize = 0;
			this.supportSize = 0;
			getStatus();
		}
	}

	public void waitHere() {
		this.mode = "WAIT";
	}

	public void attack(char _dir) {
		this.dir = _dir;
		this.mode = "ATTACK";
	}

	public void defend(char _dir) {
		this.dir = _dir;
		this.mode = "Defend";
	}

	public String getMode() {
		return this.mode;
	}

	public int getDir() {
		return this.dir;
	}

	public void addCommand(int[] command) {
		commandQueue.put(command);
	}

	public void getCommand(Map m) {
		int[] command;
		if (commandQueue.getSize() > 0) {
			command = commandQueue.peek();
			command = commandQueue.peek();
			if (command[0] == 0) {
				this.mode="MOVE";
				this.targetX = command[1];
				this.targetY = command[2];
				if ((this.x == this.targetX) && (this.y == this.targetY)) {
					commandQueue.pop();
					this.mode="WAIT";
					getCommand(m);
				} else {
					this.moveDelay--;
					if (this.moveDelay <= 0) {
						move(m, targetX, targetY);

						for (int i = 0; i < battleSize; i++) {
							
							this.m.getTile(this.battleUnits[i].getX(), this.battleUnits[i].getY()).remTileable(this.battleUnits[i].getStatus()[0]);
							this.m.getTile(this.x, this.y).putTileable(this.battleUnits[i]);
							
							this.battleUnits[i].setX(this.x);
							this.battleUnits[i].setY(this.y);
							this.battleUnits[i].setDestX(this.x);
							this.battleUnits[i].setDestY(this.y);

							
							
							
							
						}

						this.moveDelay = this.movement;
					}

				}
			}
			else if(command[0]==1)
			{
				this.mode="ATTACK";
				if(commandQueue.getSize()>1)
				{
					this.mode="WAIT";
					commandQueue.pop();
				}
			}
			else if(command[0]==2)
			{
				this.mode="DEFEND";
				if(commandQueue.getSize()>1)
				{
					this.mode="WAIT";
					commandQueue.pop();
				}
			}
			else if(command[0]==3)
			{
				this.mode="WAIT";
				commandQueue.pop();
			}
		}
	}

	public void doMove(Map m) {
		if (this.powerDelay > 0) {
			if (this.mode != "SLEEP") {
				this.powerDelay--;
				if (this.powerDelay == 0) {
					this.mode = "STANDBY";
				}
			}
		} else {
			getCommand(m);
		}
	}

	public void powerUp() {
		for (int i = 0; i < size; i++) {
			if (this.allUnits[i] != null) {
				this.allUnits[i].powerUp();
			}
		}
	}

	public void powerDown() {
		System.out.println(size);
		for (int i = 0; i < size; i++) {
			if (this.allUnits[i] != null) {
				System.out.println(i);
				this.allUnits[i].powerDown();
			}
		}
	}

	public int[] getStatus() {
		int[] status = new int[9];
		status[0] = this.ID;
		status[1] = this.type;
		status[5] = 0;
		status[8] = this.player.getID();
		for (int i = 0; i < battleSize; i++) {
			if (this.battleUnits[i] != null) {
				int[] uStatus = this.battleUnits[i].getStatus();
				status[2] += uStatus[2];
				status[3] += uStatus[3];
				status[4] += uStatus[4];
				status[5] = Math.max(status[5], uStatus[5]);
				status[6] += uStatus[6];
				status[7] += uStatus[7];
			}
		}
		this.offensive = status[2];
		this.defensive = status[3];
		this.armor = status[4];
		this.movement = status[5];
		this.health = status[6];
		this.upkeep = status[7];
		return status;
	}

	public String[] gettxtStatus() {
		int[] stats = getStatus();
		String[] status = new String[10];
		status[0] = this.getTypeName(this.type);
		status[1] = "ID: " + this.ID;
		status[2] = "DMG: " + stats[2];
		status[3] = "DEF: " + stats[3];
		status[4] = "Armor: " + stats[4];
		status[5] = "Movement: " + stats[5];
		status[6] = "HP: " + stats[6];
		status[7] = "Upkeep: " + stats[7];
		status[8] = "Size: " + this.battleSize;
		status[9] = "" + this.mode;
		return status;
	}

	public String[] gettxtCommands() {
		String[] commands = { "Attack", "Defend", "Move", "Wait",
				"Decommission", "Disband", "Power down", "Power up",
				"Cancel orders" };
		return commands;
	}

	public void setHealth(int dec) {
		this.health -= dec;
	}

	public void addUnit(Unit u) {
		boolean existsBattle = false;
		boolean existsSupport = false;
		for (int i = 0; i < 10; i++) {
			if ((this.battleUnits[i] != null)
					&& (this.battleUnits[i].equals(u))) {
				existsBattle = true;
				break;
			}
		}
		for (int i = 0; i < 10; i++) {
			if ((this.supportUnits[i] != null)
					&& (this.supportUnits[i].equals(u))) {
				existsSupport = true;
				break;
			}
		}
		if (existsBattle == false) {
			if ((u.getX() == this.getX()) && ((u.getY() == this.getY()))) {
				if (existsSupport == true) {
					remSupportUnit(u);
				}
				this.battleUnits[battleSize] = u;
				u.setRally(this);
				battleSize++;
				if (existsSupport == false) {
					this.allUnits[size] = u;
					size++;
				}
			} else {
				if (existsSupport == false) {
					this.supportUnits[supportSize] = u;
					u.setRally(this);
					supportSize++;
					this.allUnits[size] = u;
					size++;
				}
			}

		}
	}

	public void remUnit(Unit u) {
		remBattleUnit(u);
		remSupportUnit(u);
	}

	public void remAllUnit(Unit u) {
		for (int i = 0; i < 10; i++) {
			if ((this.allUnits[i] != null) && (this.allUnits[i].equals(u))) {
				this.allUnits[i].setRally(null);
				this.allUnits[i] = null;
				for (int j = i; j < allUnits.length - 1; j++) {
					this.allUnits[j] = this.allUnits[j + 1];
				}
				this.allUnits[allUnits.length - 1] = null;
				size--;
				getStatus();
				break;
			}
		}
	}

	public void remBattleUnit(Unit u) {
		for (int i = 0; i < 10; i++) {
			if ((this.battleUnits[i] != null)
					&& (this.battleUnits[i].equals(u))) {
				this.battleUnits[i].setRally(null);
				this.battleUnits[i] = null;
				for (int j = i; j < battleUnits.length - 1; j++) {
					this.battleUnits[j] = this.battleUnits[j + 1];
				}
				this.battleUnits[battleUnits.length - 1] = null;
				battleSize--;
				getStatus();
				break;
			}
		}
	}

	public void remSupportUnit(Unit u) {
		for (int i = 0; i < 10; i++) {
			if ((this.supportUnits[i] != null)
					&& (this.supportUnits[i].equals(u))) {
				this.supportUnits[i].setRally(null);
				this.supportUnits[i] = null;
				for (int j = i; j < supportUnits.length - 1; j++) {
					this.supportUnits[j] = this.supportUnits[j + 1];
				}
				this.supportUnits[supportUnits.length - 1] = null;
				supportSize--;
				getStatus();
				break;
			}
		}
	}

	public Unit[][] getUnits() {
		Unit[][] units = new Unit[2][];
		units[0] = this.battleUnits;
		units[0] = this.supportUnits;
		return units;
	}

	public int[] getSize()
	{
		int[] size={this.size,this.battleSize,this.supportSize};
		return size;
	}

	public void destroy() {
		for (int i = 0; i < battleUnits.length; i++)
			battleUnits[i] = null;
		this.battleSize = 0;
	}

	private int ss, gg, a, b;
	private int[] s, g;

	public void setDestination(int _x, int _y) {
		if ((targetX + _x) >= 0 && (targetX + _x) < 29 && (targetY + _y) >= 0
				&& (targetY + _y) < 29) {
			this.targetX += _x;
			this.targetY += _y;
		}
	}

	public int move(Map m, int x, int y) {
		char c1 = '-', c2 = '-';
		int w = m.width();
		int numOfElem = w * m.height();
		s = new int[numOfElem];
		g = new int[numOfElem];
		for (int i = 0; i < numOfElem; i++) {
			s[i] = -1;
			g[i] = -1;
			char ch = m.getTileLabel(i % w, i / w);
			if (ch == '*' || ch == '&')
				s[i] = -2;
			if (i % w == getX() && i / w == getY()) {
				ss = i;
			}
			if (i % w == x && i / w == y) {
				gg = i;
			}
		}
		a = gg;
		b = gg;
		while (a != ss) {
			add(a, 1);
			add(a, -1);
			add(a, w);
			add(a, -w);
			a = s[a];
		}

		int count = 0;
		while (a != gg) {
			if (count == 0)
				c1 = sv(g[a]);
			else if (count == 1)
				c2 = sv(g[a]);
			count++;
			a += g[a];
		}

		int dir = evalDirection(c1, c2);

		switch (dir) {
		case 1:
			m.displace(this.x, this.y, this.x - 1, this.y + 1, this);
			break;
		case 2:
			m.displace(this.x, this.y, this.x - 0, this.y + 1, this);
			break;
		case 3:
			m.displace(this.x, this.y, this.x + 1, this.y + 1, this);
			break;
		case 4:
			m.displace(this.x, this.y, this.x - 1, this.y + 0, this);
			break;
		case 6:
			m.displace(this.x, this.y, this.x + 1, this.y + 0, this);
			break;
		case 7:
			m.displace(this.x, this.y, this.x - 1, this.y - 1, this);
			break;
		case 8:
			m.displace(this.x, this.y, this.x - 0, this.y - 1, this);
			break;
		case 9:
			m.displace(this.x, this.y, this.x + 1, this.y - 1, this);
			break;
		default:
			m.displace(this.x, this.y, this.x + 0, this.y + 0, this);
		}
		Tile tempTile = m.getTile(this.x, this.y);

		if (tempTile.hasItem()) {

			if (this.battleSize > 0) {
				Unit bU = this.battleUnits[0];

				Item it = tempTile.getItem();
				int itType = it.getType();
				if (itType == 40) {

					bU.incHealth();
					Item[] iArray = it.getItemArray();
					iArray[it.getIndex()] = null;
				}

				else if (itType == 41) {
					bU.incArmor();
					Item[] iArray = it.getItemArray();
					iArray[it.getIndex()] = null;
				}

				tempTile.deleteItem();
			}

		}

		return dir;
	}

	private int evalDirection(char c1, char c2) {
		int dir = -1;
		if ((c1 == 'N' && c2 == 'N') || (c1 == 'N' && c2 == '-'))
			dir = 8;
		else if ((c1 == 'W' && c2 == 'W') || (c1 == 'W' && c2 == '-'))
			dir = 4;
		else if ((c1 == 'S' && c2 == 'S') || (c1 == 'S' && c2 == '-'))
			dir = 2;
		else if ((c1 == 'E' && c2 == 'E') || (c1 == 'E' && c2 == '-'))
			dir = 6;
		else if ((c1 == 'E' && c2 == 'N') || (c1 == 'N' && c2 == 'E'))
			dir = 9;
		else if ((c1 == 'E' && c2 == 'S') || (c1 == 'S' && c2 == 'E'))
			dir = 3;
		else if ((c1 == 'W' && c2 == 'N') || (c1 == 'N' && c2 == 'W'))
			dir = 7;
		else if ((c1 == 'W' && c2 == 'S') || (c1 == 'S' && c2 == 'W'))
			dir = 1;
		else
			dir = -1;
		return dir;
	}

	private void add(int p, int o) {
		if (p + o > -1) {
			if (s[p + o] == -1) {
				s[b] = p + o;
				b = p + o;
				g[p + o] = -o;
			}
		}
	}

	private char sv(int o) {
		if (o > 0)
			return (o == 1) ? 'E' : 'S';
		return (o == -1) ? 'W' : 'N';
	}

}
